﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Text;
using System.Threading;
using System.Collections;
using System.Data;

namespace Citi.HeadCount.WebUI.Util
{
    public class ExcelGenerator
    {
        public MemoryStream GerarArquivo<T>(Dictionary<string, string> headers, IEnumerable<T> registros, int colunaInicioSubGrid = 0)
        {
            var linha = new StringBuilder();
            var stream = new MemoryStream();
            var tw = new StreamWriter(stream, Encoding.UTF8);
            var separadorListas = ";"; //Thread.CurrentThread.CurrentUICulture.TextInfo.ListSeparator;

            foreach (var head in headers)
                linha.Append(head.Key).Append(separadorListas);

            tw.WriteLine(linha.ToString().TrimEnd(separadorListas.ToCharArray()));

            Dictionary<string, string> cabecalhosSubGrid = null;
            Dictionary<string, string> cabecalhosGrid = headers;

            if (colunaInicioSubGrid > 0)
            {
                cabecalhosSubGrid = headers.Where((c, i) => i >= colunaInicioSubGrid).ToDictionary(c => c.Key, c => c.Value);
                cabecalhosGrid = headers.Where((c, i) => i < colunaInicioSubGrid).ToDictionary(c => c.Key, c => c.Value);
            }

            foreach (var registro in registros)
            {
                linha = new StringBuilder();

                foreach (var cabecalho in cabecalhosGrid)
                {
                    if (cabecalho.Value.Contains("["))
                    {
                        var propertyInfo = registro.GetType().GetProperty(cabecalho.Value.Split('[')[0]);

                        if (propertyInfo == null)
                        {
                            linha.Append("-").Append(separadorListas);
                            continue;
                        }

                        var value = (IList<string>)propertyInfo.GetValue(registro, null);

                        var index = int.Parse(cabecalho.Value.Split('[')[1].Replace("]", string.Empty));

                        if (index > value.Count() - 1)
                        {
                            linha.Append("-").Append(separadorListas);
                            continue;
                        }

                        linha.Append(value[index].Replace(";", string.Empty)).Append(separadorListas);
                    }
                    else
                        linha.Append(CriarColuna(cabecalho, registro)).Append(separadorListas);
                }

                CriarLinhasSubGrid(linha, colunaInicioSubGrid, registro, cabecalhosSubGrid);
                tw.WriteLine(linha.ToString().TrimEnd(';'));
            }

            tw.Flush();
            tw.Close();

            return stream;
        }

        private void CriarLinhasSubGrid<T>(StringBuilder linha, int colunaInicioSubGrid, T registro, Dictionary<string, string> cabecalhosSubGrid)
        {
            if (cabecalhosSubGrid == null) return;

            var propriedadeEnumerable = cabecalhosSubGrid.ElementAt(0).Value.Split('.')[0];

            if (registro == null) return;

            var lista = registro.GetType().GetProperty(propriedadeEnumerable).GetValue(registro, null);

            if (lista is IEnumerable)
            {
                var colunasIniciais = new String(';', colunaInicioSubGrid);

                var linhaPai = linha.ToString();
                var primeiroItemSubGrid = true;
                foreach (var item in (IEnumerable)lista)
                {
                    if (!primeiroItemSubGrid)
                    {
                        linha.AppendLine();
                        linha.Append(linhaPai);
                    }
                    primeiroItemSubGrid = false;
                    foreach (var cabecalhoSubGrid in cabecalhosSubGrid)
                    {
                        var cabecalho = new KeyValuePair<string, string>(cabecalhoSubGrid.Key, cabecalhoSubGrid.Value.Remove(0, cabecalhoSubGrid.Value.IndexOf('.') + 1));

                        linha.Append(CriarColuna(cabecalho, item)).Append(';');
                    }
                }
            }
        }

        private string CriarColuna(KeyValuePair<string, string> cabecalho, object registro)
        {
            var propriedades = cabecalho.Value.Split('.').ToList();
            var linha = new StringBuilder();

            if (propriedades.Count > 1)
            {
                if (registro != null)
                {
                    var propriedade = registro.GetType().GetProperty(propriedades[0]);

                    if (propriedade != null)
                    {
                        var filho = propriedade.GetValue(registro, null);
                        var cabecalhoFilho = new KeyValuePair<string, string>(cabecalho.Key, cabecalho.Value.Substring(propriedades[0].Count() + 1));

                        linha.Append(CriarColuna(cabecalhoFilho, filho));
                    }
                    else
                    {
                        return String.Empty;
                    }
                }
            }
            else
            {
                string idNaoEncontrado = string.Empty;

                //try
                //{
                //    NHibernateUtil.Initialize(registro);
                //}
                //catch (ObjectNotFoundException onfex)
                //{
                //    idNaoEncontrado = onfex.Identifier.ToString();
                //    registro = null;
                //}

                if (registro != null)
                {
                    if (registro.GetType().GetProperty(cabecalho.Value.Trim()) != null)
                    {
                        var valor = registro.GetType().GetProperty(cabecalho.Value.Trim()).GetValue(registro, null);

                        var valorRetorno = ConsultarValorDaPropriedade(valor) ?? valor;

                        if (valorRetorno != null)
                            linha.Append(valorRetorno.ToString());
                    }
                }
                else if (!string.IsNullOrEmpty(idNaoEncontrado))
                {
                    linha.AppendFormat("NÃO ENCONTRADO - {0}", idNaoEncontrado);
                }
            }

            return linha.ToString();
        }

        private object ConsultarValorDaPropriedade(object valor)
        {
            if (valor == null) return null;
          
            if (valor is bool)
            {
                switch ((bool)valor)
                {
                    case false:
                        return "Não";
                    case true:
                        return "Sim";
                    default:
                        return valor;
                }
            }
            if (valor is DateTime)
            {
                return Convert.ToDateTime(valor);
            }
            if (valor is Enum)
            {
                //return ((Enum)valor).GetDescription();
            }
            return valor;
        }

        public MemoryStream GerarArquivo(DataTable dataTable)
        {
            var stream = new MemoryStream();
            var tw = new StreamWriter(stream, Encoding.UTF8);

            int iColCount = dataTable.Columns.Count;

            for (int i = 0; i < iColCount; i++)
            {
                tw.Write(dataTable.Columns[i]);

                if (i < iColCount - 1)
                    tw.Write(";");
            }

            tw.Write(tw.NewLine);

            foreach (DataRow dr in dataTable.Rows)
            {
                for (int i = 0; i < iColCount; i++)
                {
                    if (!Convert.IsDBNull(dr[i]))
                        tw.Write(dr[i].ToString());

                    if (i < iColCount - 1)
                        tw.Write(";");
                }

                tw.Write(tw.NewLine);
            }

            tw.Flush();
            return stream;
        }

    }

}